<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div>
    <h2>一、是什么</h2>
    <div>在JavaScript中，new操作符用于创建一个给定构造函数的实例对象</div>
    <ul>
      <li>new 通过构造函数 Person 创建出来的实例可以访问到构造函数中的属性</li>
      <li>new 通过构造函数 Person 创建出来的实例可以访问到构造函数原型链中的属性（即实例与构造函数通过原型链连接了起来）</li>
    </ul>
  </div>
  <div>
    <h4>构造函数中返回一个原始值，然而这个返回值并没有作用</h4>
    <h4>构造函数如果返回值为一个对象，那么这个返回值会被正常使用</h4>
  </div>
  <div>
    <h2>二、流程</h2>
    <div>
      <div>new关键字主要做了以下的工作：</div>
      <ul>
        <li>创建一个新的对象obj</li>
        <li>将对象与构建函数通过原型链连接起来</li>
        <li>将构建函数中的this绑定到新建的对象obj上</li>
        <li>根据构建函数返回类型作判断，如果是原始值则被忽略，如果是返回对象，需要正常处理</li>
      </ul>
    </div>
    <h2>三、手写new操作符</h2>
  </div>
  <script>



    // 现在在构建函数中显式加上返回值，并且这个返回值是一个原始类型
    // 可以发现，构造函数中返回一个原始值，然而这个返回值并没有作用
    // function Test(name) {
    //   this.name = name
    //   return 1
    // }
    // const t = new Test('xxx')
    // console.log(t) // 'xxx'


    // 从上面可以发现，构造函数如果返回值为一个对象，那么这个返回值会被正常使用
    // function Test(name) {
    //   this.name = name
    //   // console.log(this) // Test { name: 'xxx' }
    //   return { age: 26 }
    // }
    // const t = new Test('xxx')
    // // console.log(t) // { age: 26 }
    // console.log(t.name) // 'undefined'


    // function Person(name, age) {
    //   this.name = name;
    //   this.age = age;
    // }
    // 创建一个空对象
    // 将新对象的[[prototype]]指向Person.prototype
    // {}.__proto__ = Person.rrototype
    // 将Person构造函数的this设置为新创建的对象，执行
    // 构造函数Person没有return语句，则将该新创建的对象返回

    // const person1 = new Person('Tom', 20)
    // console.log(person1)  // Person {name: "Tom", age: 20}
    // console.log(person1.neme); // 'Tom'


    // 动手来实现一下new
    function mynew(Func, ...args) {
      // 1.创建一个新对象
      const obj = {}
      // 2.新对象原型指向构造函数原型对象
      obj.__proto__ = Func.prototype
      // 3.将构建函数的this指向新对象
      let result = Func.apply(obj, args)
      // 4.根据返回值判断
      return result instanceof Object ? result : obj
    }

    function Person(name, age) {
        this.name = name;
        this.age = age;
    }

    Person.prototype.say = function () {
        console.log(this.name)
    }

    let p = mynew(Person, "huihui", 123)

    //     
    // function mynew(Person, "huihui", 123) {
    //   // 1.创建一个新对象
    //   const obj = {}
    //   // 2.新对象原型指向构造函数原型对象
    //   obj.__proto__ = Person.prototype
    //   // 3.将构建函数的this指向新对象
    //   let result = Person.apply(obj, "huihui", 123)
    //   // 4.根据返回值判断
    //   result = {
    //     neme:'huihui',
    //     age:'123'
    //   }
    //   return result instanceof Object ? result : obj
    // }

    console.log(result) // Person {name: "huihui", age: 123}
    result.say() // huihui
  </script>
</body>

</html>